{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# GPU-accelerated interactive visualization of single cells with RAPIDS, Scanpy and Plotly Dash"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Copyright (c) 2020, NVIDIA CORPORATION.\n",
    "\n",
    "Licensed under the Apache License, Version 2.0 (the \"License\") you may not use this file except in compliance with the License. You may obtain a copy of the License at\n",
    "\n",
    "    http://www.apache.org/licenses/LICENSE-2.0 \n",
    "\n",
    "Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this notebook, we cluster cells based on a single-cell RNA-seq count matrix, and produce an interactive visualization of the clustered cells that allows for further analysis of the data in a browser window."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For demonstration purposes, we use a dataset of ~70,000 human lung cells from Travaglini et al. 2020 (https://www.biorxiv.org/content/10.1101/742320v2) and label cells using the ACE2, TMPRSS2, and EPCAM marker genes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import requirements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import scanpy as sc\n",
    "import anndata\n",
    "\n",
    "import sys\n",
    "import time\n",
    "\n",
    "import os, wget\n",
    "\n",
    "import cudf\n",
    "import cupy as cp\n",
    "\n",
    "from cuml.decomposition import PCA\n",
    "from cuml.manifold import TSNE\n",
    "from cuml.cluster import KMeans\n",
    "from cuml.preprocessing import StandardScaler\n",
    "\n",
    "import rapids_scanpy_funcs\n",
    "\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore', 'Expected ')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We use the RAPIDS memory manager on the GPU to control how memory is allocated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "import rmm\n",
    "\n",
    "rmm.reinitialize(\n",
    "    managed_memory=True, # Allows oversubscription\n",
    "    pool_allocator=False, # default is False\n",
    "    devices=0, # GPU device IDs to register. By default registers only GPU 0.\n",
    ")\n",
    "\n",
    "cp.cuda.set_allocator(rmm.rmm_cupy_allocator)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Input data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the cell below, we provide the path to the `.h5ad` file containing the count matrix to analyze. Please see the README for instructions on how to download the dataset we use here.\n",
    "\n",
    "We recommend saving count matrices in the sparse .h5ad format as it is much faster to load than a dense CSV file. To run this notebook using your own dataset, please see the README for instructions to convert your own count matrix into this format. Then, replace the path in the cell below with the path to your generated `.h5ad` file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "input_file = \"../data/krasnow_hlca_10x.sparse.h5ad\"\n",
    "\n",
    "if not os.path.exists(input_file):\n",
    "    print('Downloading import file...')\n",
    "    os.makedirs('../data', exist_ok=True)\n",
    "    wget.download('https://rapids-single-cell-examples.s3.us-east-2.amazonaws.com/krasnow_hlca_10x.sparse.h5ad',\n",
    "                  input_file)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# marker genes\n",
    "RIBO_GENE_PREFIX = \"RPS\" # Prefix for ribosomal genes to regress out\n",
    "markers = [\"ACE2\", \"TMPRSS2\", \"EPCAM\"] # Marker genes for visualization\n",
    "\n",
    "# filtering cells\n",
    "min_genes_per_cell = 200 # Filter out cells with fewer genes than this expressed \n",
    "max_genes_per_cell = 6000 # Filter out cells with more genes than this expressed \n",
    "\n",
    "# filtering genes\n",
    "min_cells_per_gene = 1 # Filter out genes expressed in fewer cells than this\n",
    "n_top_genes = 5000 # Number of highly variable genes to retain\n",
    "\n",
    "# PCA\n",
    "n_components = 50 # Number of principal components to compute\n",
    "\n",
    "# KNN\n",
    "n_neighbors = 15 # Number of nearest neighbors for KNN graph\n",
    "knn_n_pcs = 50 # Number of principal components to use for finding nearest neighbors\n",
    "\n",
    "# UMAP\n",
    "umap_min_dist = 0.3 \n",
    "umap_spread = 1.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load and Prepare Data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We load the sparse count matrix from an `h5ad` file using Scanpy. The sparse count matrix will then be placed on the GPU. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 160 ms, sys: 662 ms, total: 822 ms\n",
      "Wall time: 1.08 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "adata = sc.read(input_file)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(65662, 26485)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "adata.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.19 s, sys: 1.18 s, total: 2.37 s\n",
      "Wall time: 2.37 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "genes = cudf.Series(adata.var_names)\n",
    "barcodes = cudf.Series(adata.obs_names)\n",
    "sparse_gpu_array = cp.sparse.csr_matrix(adata.X)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preprocessing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Filter"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We filter the count matrix to remove cells with an extreme number of genes expressed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 679 ms, sys: 676 ms, total: 1.35 s\n",
      "Wall time: 1.38 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sparse_gpu_array, barcodes = rapids_scanpy_funcs.filter_cells(sparse_gpu_array, min_genes=min_genes_per_cell, max_genes=max_genes_per_cell, barcodes=barcodes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some genes will now have zero expression in all cells. We filter out such genes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 802 ms, sys: 238 ms, total: 1.04 s\n",
      "Wall time: 1.04 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sparse_gpu_array, genes = rapids_scanpy_funcs.filter_genes(sparse_gpu_array, genes, min_cells=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The size of our count matrix is now reduced."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(65462, 22058)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sparse_gpu_array.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Normalize"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We normalize the count matrix so that the total counts in each cell sum to 1e4."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 2.59 ms, sys: 0 ns, total: 2.59 ms\n",
      "Wall time: 3.73 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sparse_gpu_array = rapids_scanpy_funcs.normalize_total(sparse_gpu_array, target_sum=1e4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we log transform the count matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 52.8 ms, sys: 42 ms, total: 94.8 ms\n",
      "Wall time: 96.1 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sparse_gpu_array = sparse_gpu_array.log1p()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Select Most Variable Genes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We first save the 'raw' expression values of the ACE2 and TMPRSS2 genes to use for labeling cells afterward. We will also store the expression of an epithelial marker gene (EPCAM)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 292 ms, sys: 186 ms, total: 478 ms\n",
      "Wall time: 492 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "tmp_norm = sparse_gpu_array.tocsc()\n",
    "marker_genes_raw = {\n",
    "    (\"%s_raw\" % marker): tmp_norm[:, genes[genes == marker].index[0]].todense().ravel()\n",
    "    for marker in markers\n",
    "}\n",
    "\n",
    "del tmp_norm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We identify the top 5000 variable genes using the `cellranger` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1e+03 ns, sys: 1e+03 ns, total: 2 µs\n",
      "Wall time: 4.29 µs\n"
     ]
    }
   ],
   "source": [
    "%time\n",
    "hvg = rapids_scanpy_funcs.highly_variable_genes(sparse_gpu_array, genes, n_top_genes=5000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We filter the count matrix to retain only the 5000 most variable genes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 203 ms, sys: 91.6 ms, total: 295 ms\n",
      "Wall time: 304 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(65462, 5000)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%time\n",
    "sparse_gpu_array = sparse_gpu_array[:, hvg]\n",
    "genes = genes[hvg].reset_index(drop=True)\n",
    "sparse_gpu_array.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Regress out confounding factors (number of counts, ribosomal gene expression)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now perform regression on the count matrix to correct for confounding factors -  for example purposes, we use the number of counts and the expression of ribosomal genes. Many workflows use the expression of mitochondrial genes (named starting with `MT-`)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now calculate the total counts and the percentage of ribosomal counts for each cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 35 ms, sys: 20.4 ms, total: 55.4 ms\n",
      "Wall time: 56.4 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "ribo_genes = genes.str.startswith(RIBO_GENE_PREFIX)\n",
    "\n",
    "n_counts = sparse_gpu_array.sum(axis=1)\n",
    "percent_ribo = (sparse_gpu_array[:,ribo_genes].sum(axis=1) / n_counts).ravel()\n",
    "\n",
    "n_counts = cp.array(n_counts).ravel()\n",
    "percent_ribo = cp.array(percent_ribo).ravel()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And perform regression:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 15.6 s, sys: 20 s, total: 35.6 s\n",
      "Wall time: 36 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sparse_gpu_array = rapids_scanpy_funcs.regress_out(sparse_gpu_array, n_counts, percent_ribo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Scale"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we scale the count matrix to obtain a z-score and apply a cutoff value of 10 standard deviations, obtaining the preprocessed count matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.2 s, sys: 754 ms, total: 1.96 s\n",
      "Wall time: 2.02 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sparse_gpu_array = cp.clip(sparse_gpu_array, a_min = -10, a_max=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Cluster & Visualize"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We store the preprocessed count matrix as an AnnData object, which is currently in host memory. \n",
    "We also add the barcodes of the filtered cells, and the expression levels of the marker genes, to the annData object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 285 ms, sys: 448 ms, total: 733 ms\n",
      "Wall time: 731 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "\n",
    "adata = anndata.AnnData(sparse_gpu_array.get())\n",
    "adata.var_names = genes.to_pandas()\n",
    "adata.obs_names = barcodes.to_pandas()\n",
    "for name, data in marker_genes_raw.items():\n",
    "    adata.obs[name] = data.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reduce"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We use PCA to reduce the dimensionality of the matrix to its top 50 principal components."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.44 s, sys: 1.3 s, total: 2.75 s\n",
      "Wall time: 2.75 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "adata.obsm[\"X_pca\"] = PCA(n_components=n_components, output_type=\"numpy\").fit_transform(adata.X)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### UMAP + clustering"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We visualize the cells using the UMAP algorithm in Rapids. Before UMAP, we need to construct a k-nearest neighbors graph in which each cell is connected to its nearest neighbors. This can be done conveniently using rapids functionality already integrated into Scanpy.\n",
    "\n",
    "Note that Scanpy uses an approximation to the nearest neighbors on the CPU while the GPU version performs an exact search. While both methods are known to yield useful results, some differences in the resulting visualization and clusters can be observed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 4.31 s, sys: 414 ms, total: 4.73 s\n",
      "Wall time: 4.93 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sc.pp.neighbors(adata, n_neighbors=n_neighbors, n_pcs=knn_n_pcs, method='rapids')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The UMAP function from Rapids is also integrated into Scanpy."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING: .obsp[\"connectivities\"] have not been computed using umap\n",
      "CPU times: user 268 ms, sys: 240 ms, total: 509 ms\n",
      "Wall time: 508 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "sc.tl.umap(adata, min_dist=umap_min_dist, spread=umap_spread, method='rapids')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we use the Leiden algorithm for graph-based clustering."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 79.6 ms, sys: 16.4 ms, total: 96 ms\n",
      "Wall time: 95 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "adata.obs['leiden'] = rapids_scanpy_funcs.leiden(adata, resolution=0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We plot the cells using the UMAP visualization, using the Louvain clusters as labels."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sc.pl.umap(adata, color=[\"leiden\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Defining re-clustering function for interactive visualization "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we have shown above, the speed of RAPIDS allows us to run steps like dimension reduction, clustering and visualization in seconds or even less. In the sections below, we create an interactive visualization that takes advantage of this speed by allowing users to cluster and analyze selected groups of cells at the click of a button."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we create a function named `re_cluster`. This function can be called on selected groups of cells. According to the function defined below, PCA, KNN, UMAP and Louvain clustering will be re-computed upon the selected cells. You can customize this function for your desired analysis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "def re_cluster(adata):\n",
    "    \n",
    "    #### Function to repeat clustering and visualization on subsets of cells\n",
    "    #### Runs PCA, KNN, UMAP and Leiden clustering on selected cells.\n",
    "    adata.obsm[\"X_pca\"] = PCA(n_components=n_components, output_type=\"numpy\").fit_transform(adata.X)\n",
    "    sc.pp.neighbors(adata, n_neighbors=n_neighbors, n_pcs=knn_n_pcs, method='rapids')\n",
    "    sc.tl.umap(adata, min_dist=umap_min_dist, spread=umap_spread, method='rapids')\n",
    "    adata.obs['leiden'] = rapids_scanpy_funcs.leiden(adata)\n",
    "\n",
    "    return adata"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating an interactive visualization with Plotly Dash"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"https://github.com/clara-parabricks/rapids-single-cell-examples/blob/master/images/dashboard.png?raw=true\" alt=\"Interactive Dashboard\" width=\"400\"/>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below, we create the interactive visualization using the `adata` object and the re-clustering function defined above. To learn more about how this visualization is built, see `visualize.py`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you run the cell below, it returns a link. Click on this link to access the interactive visualization within your browser. \n",
    "\n",
    "Once opened, click the `Directions` button for instructions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dash is running on http://0.0.0.0:5000/\n",
      "\n",
      " * Serving Flask app 'visualize' (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: on\n"
     ]
    }
   ],
   "source": [
    "import visualize\n",
    "\n",
    "v = visualize.Visualization(adata, markers, re_cluster_callback=re_cluster)\n",
    "v.start('0.0.0.0')\n",
    "1\n",
    "selected_cells = v.new_df "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Within the dashboard, you can select cells using a variety of methods. You can then cluster, visualize and analyze the selected cells using the tools provided. Click on the `Directions` button for details. \n",
    "\n",
    "To export the selected cells and the results of your analysis back to the notebook, click the `Export to Dataframe` button. This exports the results of your analysis back to this notebook, and closes the interactive dashboard. \n",
    "\n",
    "See the next section for instructions on how to use the exported data."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exporting a selection of cells from the dashboard"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you exported a selection cells from the interactive visualization, your selection will be available here as a data frame named `selected_cells`. The `labels` column of this dataframe contains the newly generated cluster labels assigned to these selected cells."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0, 0)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "Empty DataFrame\n",
       "Columns: []\n",
       "Index: []"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(selected_cells.shape)\n",
    "selected_cells.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can link the selected cells to the original `adata` object using the cell barcodes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "adata_selected_cells = adata[selected_cells.barcode.to_array(),:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "adata_selected_cells = adata[selected_cells.barcode.to_array(),:]\n",
    "adata_selected_cells"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (rapidgenomics_2112_2)",
   "language": "python",
   "name": "rapidgenomics_2112_2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
